﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Game
{
    public class Set<TEnum> : IEnumerable where TEnum : struct
    {
        private static uint[] TSetBitMask = 
        {
	        0x80000000,	0x40000000,	0x20000000,	0x10000000,
	        0x8000000,	0x4000000,	0x2000000,	0x1000000,
	        0x800000,	0x400000,	0x200000,	0x100000,
	        0x80000,	0x40000,	0x20000,	0x10000,
	        0x8000,		0x4000,		0x2000,		0x1000,
	        0x800,		0x400,		0x200,		0x100,
	        0x80,		0x40,		0x20,		0x10,
	        0x8,		0x4,		0x2,		0x1 
        };

        public Set()
        {
            mMask = 0x0;
        }
        
        public Set(uint mask)
        {
            mMask = mask;
        }

        public Set(TEnum key)
        {
            mMask = 0x0;
            Include(key);
        }

        public void Reset()
        {
            mMask = 0x0;
        }

        public bool IsEmpty()
        {
            return mMask == 0x0;
        }

        public void Apply(TEnum key, bool mode)
        {
            if (mode)
            {
                Include(key);
            }
            else
            {
                Exclude(key);
            }
        }

        public void Include(TEnum key)
        {
            mMask |= TSetBitMask[(int)((object)key)];
        }

        public void Exclude(TEnum key) 
        {
            mMask &= ~TSetBitMask[(int)((object)key)];
        }

        public bool In(TEnum key)
        {
            return In((int)((object)key));
        }

        public bool In(int value)
        {
            return (mMask & TSetBitMask[value]) == TSetBitMask[value];
        }

        public uint GetMask()
        {
            return mMask;
        }

        private uint mMask;

        public IEnumerator GetEnumerator()
        {
            return new SetEnumerator(this);
        }

        // Inner class implements IEnumerator interface:
        private class SetEnumerator : IEnumerator
        {
            private Set<TEnum> mSet;
            private static int mLength = Enum.GetValues(typeof(TEnum)).Length;
            private int mPosition = -1;

            public SetEnumerator(Set<TEnum> set)
            {
                mSet = set;
            }

            // Declare the MoveNext method required by IEnumerator:
            public bool MoveNext()
            {
                while (++mPosition < mLength)
                {
                    if(mSet.In(mPosition))
                    {
                        return true;
                    }
                }
                return false;
            }

            // Declare the Reset method required by IEnumerator:
            public void Reset()
            {
                mPosition = -1;
            }

            // Declare the Current property required by IEnumerator:
            public object Current
            {
                get
                {
                    return mPosition;
                }
            }
        }
    }
}